import { type Ref } from 'vue'
import { showToast } from 'vant'
import { fetchJsApiSignature } from '@/api/lanxin'

// 全局 lx 对象的声明，避免 TS 报错
declare const lx: any

// 照片类型定义
export interface PhotoItem {
  url: string
  file: File
}

// 拍照选项
export interface ChooseImageOptions {
  maxCount?: number // 最大照片数量，默认 5
  sourceType?: ('camera' | 'album')[] // 图片来源，默认只允许拍照 ['camera']
  quality?: 'low' | 'medium' | 'high' // 图片质量，默认 'low'
  onSuccess?: (photos: PhotoItem[]) => void // 成功回调
  onFail?: (error: any) => void // 失败回调
  fallbackToBrowser?: boolean // 蓝信不可用时是否使用浏览器文件选择，默认 true
}

// 全局状态（所有使用该 composable 的组件共享）
let lanxinReady = false
let lanxinInitStarted = false
let pendingCallback: (() => void) | null = null

// 初始化蓝信 JSAPI（签名在后端计算，前端只获取并使用）
async function initLanxinJsapiIfNeeded(callback?: () => void) {
  if (lanxinReady) {
    if (callback) callback()
    return
  }
  if (lanxinInitStarted) {
    if (callback) pendingCallback = callback
    return
  }
  lanxinInitStarted = true
  if (callback) pendingCallback = callback

  try {
    if (typeof lx?.config !== 'function') {
      console.warn('未检测到 lx 对象，可能不在蓝信环境，跳过 JSAPI 初始化')
      pendingCallback = null
      return
    }
    const currentUrl = window.location.href.split('#')[0]
    const signatureData = await fetchJsApiSignature(currentUrl)
    const appId = signatureData.appId || (window as any).APP_CONFIG?.lanxinAppId
    if (!appId) {
      console.warn('未获取到 appId（签名未返回且未在 APP_CONFIG 配置），无法初始化蓝信 JSAPI')
      showToast('蓝信 appId 缺失，无法启用拍照接口')
      pendingCallback = null
      return
    }
    lx.config({
      appId,
      timestamp: signatureData.timestamp,
      nonceStr: signatureData.noncestr,
      signature: signatureData.signature,
    })
    if (typeof lx.ready === 'function') {
      lx.ready(function () {
        lanxinReady = true
        if (pendingCallback) {
          pendingCallback()
          pendingCallback = null
        }
      })
    }
    if (typeof lx.error === 'function') {
      lx.error(function (reason: any) {
        lanxinReady = false
        console.error('蓝信 JSAPI 鉴权失败: ', reason)
        showToast(`蓝信鉴权失败: ${reason?.message || '未知错误'}`)
        pendingCallback = null
      })
    }
  } catch (e: any) {
    lanxinReady = false
    console.error('初始化蓝信 JSAPI 失败: ', e)
    showToast(`获取签名失败: ${e?.message || '未知错误'}`)
    pendingCallback = null
  }
}

function base64ToFile(base64: string, mimeType = 'image/jpeg', fileName?: string): File {
  const arr = base64.split(',')
  const pureBase64 = arr.length > 1 ? arr[1] : arr[0]
  const bstr = atob(pureBase64)
  let n = bstr.length
  const u8arr = new Uint8Array(n)
  while (n--) u8arr[n] = bstr.charCodeAt(n)
  return new File([u8arr], fileName || `photo_${Date.now()}.jpg`, { type: mimeType })
}

function doLanxinChooseImage(currentPhotos: PhotoItem[], options: ChooseImageOptions): void {
  const maxCount = options.maxCount || 5
  const remaining = maxCount - (currentPhotos?.length || 0)
  if (remaining <= 0) {
    showToast(`最多只能上传${maxCount}张照片`)
    return
  }
  if (!lanxinReady || typeof lx?.media?.chooseImage !== 'function') {
    console.warn('蓝信未就绪或 chooseImage 不可用')
    if (options.fallbackToBrowser !== false) {
      useBrowserFileInput(currentPhotos, maxCount, options)
    }
    return
  }
  try {
    lx.media.chooseImage({
      count: Math.max(1, remaining),
      sourceType: options.sourceType || ['camera'],
      quality: options.quality || 'low',
      success: (res: any) => {
        const files = Array.isArray(res?.tempFiles) ? res.tempFiles : []
        const newPhotos: PhotoItem[] = []
        files.forEach((item: any) => {
          if ((currentPhotos?.length || 0) + newPhotos.length >= maxCount) return
          const mime = item?.type || 'image/jpeg'
          const base64 = item?.base64 || ''
          if (!base64) return
          const dataUrl = base64.startsWith('data:') ? base64 : `data:${mime};base64,${base64}`
          const file = base64ToFile(dataUrl, mime, item?.name)
          newPhotos.push({ url: dataUrl, file })
        })
        options.onSuccess && options.onSuccess(newPhotos)
      },
      fail: (err: any) => {
        console.error('蓝信拍照失败: ', err)
        showToast(`打开相机失败: ${err?.message || '未知错误'}`)
        if (options.onFail) options.onFail(err)
        else if (options.fallbackToBrowser !== false) useBrowserFileInput(currentPhotos, maxCount, options)
      }
    })
  } catch (err: any) {
    console.error('调用蓝信拍照异常: ', err)
    showToast(`调用相机异常: ${err?.message || '未知错误'}`)
    if (options.onFail) options.onFail(err)
    else if (options.fallbackToBrowser !== false) useBrowserFileInput(currentPhotos, maxCount, options)
  }
}

function useBrowserFileInput(
  currentPhotos: PhotoItem[],
  maxCount: number,
  options: ChooseImageOptions
): void {
  const input = document.createElement('input')
  input.type = 'file'
  input.accept = 'image/*'
  input.multiple = true
  input.onchange = (e: any) => {
    const files = Array.from(e.target.files) as File[]
    const newPhotos: PhotoItem[] = []
    files.forEach(file => {
      if ((currentPhotos?.length || 0) + newPhotos.length < maxCount) {
        const reader = new FileReader()
        reader.onload = (evt: any) => {
          newPhotos.push({ url: evt.target.result as string, file })
          if (newPhotos.length === files.length ||
              (currentPhotos?.length || 0) + newPhotos.length >= maxCount) {
            options.onSuccess && options.onSuccess(newPhotos)
          }
        }
        reader.readAsDataURL(file)
      }
    })
  }
  input.click()
}

export function useLanxinCamera(currentPhotos: Ref<PhotoItem[]>) {
  const chooseImage = (options: ChooseImageOptions = {}) => {
    if (typeof lx !== 'undefined' && typeof lx.config === 'function') {
      initLanxinJsapiIfNeeded(() => {
        doLanxinChooseImage(currentPhotos.value, options)
      })
    } else {
      if (options.fallbackToBrowser !== false) {
        useBrowserFileInput(currentPhotos.value, options.maxCount || 5, options)
      }
    }
  }
  const isLanxinAvailable = () => {
    return typeof lx !== 'undefined' && typeof lx.config === 'function'
  }
  const isLanxinReady = () => {
    return lanxinReady
  }
  return {
    chooseImage,
    isLanxinAvailable,
    isLanxinReady
  }
}


